package dbrouter

import (
	"context"
	"encoding/json"
	"fmt"
	"gopkg.in/yaml.v2"
	"os"
	"sync"
)

//yamlConfig yaml配置
type yamlConfig struct {
	cfgFile  string
	parser   *Parser
	parserMu sync.RWMutex
}

type DbYamlConf struct {
	ClusterconfYaml ClusterconfYaml `yaml:"db" json:"db"`
}
type ClusterconfYaml struct {
	ClusterMap   map[string][]ClusterinfYaml `yaml:"cluster" json:"cluster"`
	InstancesMap map[string]DbinsYaml        `yaml:"instances" json:"instances"`
}
type ClusterinfYaml struct {
	Instance string `yaml:"instance" json:"instance"`
	Match    string `yaml:"match" json:"match"`
	Express  string `yaml:"express" json:""`
}
type DbcfgYaml struct {
	Addrs  []string `yaml:"addrs" json:"addrs"`
	User   string   `yaml:"user" json:"user"`
	Passwd string   `yaml:"passwd" json:"passwd"`
}
type DbinsYaml struct {
	Cluster string    `yaml:"cluster" json:"cluster"`
	Dbtype  string    `yaml:"dbtype" json:"dbtype"`
	Dbname  string    `yaml:"dbname" json:"dbname"`
	Dbcfg   DbcfgYaml `yaml:"dbcfg" json:"dbcfg"`
}

//NewYamlConfiger 新建配置实例
func NewYamlConfiger(ctx context.Context, cfgFile string, dbChangeChan chan ConfigChange) (Configer, error) {
	fun := "NewYamlConfiger -->"
	yamlConfig := &yamlConfig{
		cfgFile: cfgFile,
	}
	err := yamlConfig.init(ctx, dbChangeChan)
	if err != nil {
		fmt.Printf("%s init yaml configer err: %s\n", fun, err.Error())
		return nil, err
	}
	return yamlConfig, nil
}

func (e *yamlConfig) init(ctx context.Context, dbChangeChan chan ConfigChange) error {
	fun := "yamlConfig.init -->"

	f, err := os.Open(e.cfgFile)
	if err != nil {
		return err
	}
	var dbYaml DbYamlConf
	err = yaml.NewDecoder(f).Decode(&dbYaml)
	if err != nil {
		return err
	}
	confJson, err := json.Marshal(dbYaml.ClusterconfYaml)
	if err != nil {
		return err
	}
	parser, err := NewParser(confJson)
	if err != nil {
		fmt.Printf("%s init db parser err: %+v\n", fun, err.Error())
		return err
	}
	e.SetParser(ctx, parser)
	//todo 此处没有考虑动态加载问题
	return nil
}

func (e *yamlConfig) GetParser(ctx context.Context) *Parser {
	e.parserMu.RLock()
	defer e.parserMu.RUnlock()

	return e.parser
}

func (e *yamlConfig) SetParser(ctx context.Context, parser *Parser) {
	e.parserMu.Lock()
	defer e.parserMu.Unlock()

	e.parser = parser
}

//GetInstanceConfig 获取实例配置
func (e *yamlConfig) GetInstanceConfig(ctx context.Context, insName, group string) *Config {
	parser := e.GetParser(ctx)
	info := parser.getInstanceConfig(insName, group)
	return &Config{
		DBType:   info.DBType,
		DBAddr:   info.DBAddr,
		DBName:   info.DBName,
		UserName: info.UserName,
		PassWord: info.PassWord,
	}
}

//GetInstanceName 根据cluster以及table 获取实例名称
func (e *yamlConfig) GetInstanceName(ctx context.Context, cluster, table string) string {
	parser := e.GetParser(ctx)
	return parser.getInstanceName(cluster, table)
}

//GetAllGroups 获取所有的渠道（default or testing or ...）
func (e *yamlConfig) GetAllGroups(ctx context.Context) []string {
	var groups []string
	parser := e.GetParser(ctx)

	for group := range parser.dbIns {
		groups = append(groups, group)
	}
	return groups
}
